package com.sunkyc.framework.system.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.sunkyc.commons.contants.GlobContants;
import com.sunkyc.commons.exception.CustomerException;
import com.sunkyc.framework.system.CacheKey.AuthroticationCacheKeys;
import com.sunkyc.framework.system.entity.LoginRole;
import com.sunkyc.framework.system.entity.SysMenu;
import com.sunkyc.framework.system.entity.SysUser;
import com.sunkyc.framework.system.entity.vo.MetaVo;
import com.sunkyc.framework.system.entity.vo.RouterVo;
import com.sunkyc.framework.system.mapper.MenuMapper;
import com.sunkyc.framework.system.mapper.RoleMapper;
import com.sunkyc.framework.system.mapper.SysMenuMapper;
import com.sunkyc.framework.system.service.*;
import com.sunkyc.framework.utils.IpUtils;
import com.sunkyc.framework.utils.RedisUtils;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class LoginServiceImpl implements LoginService {

    //private final LoginUserMapper baseMapper;
    private final RoleMapper roleMapper;
    private final MenuMapper menuMapper;
    private final SysMenuMapper sysMenuMapper;

    private final SysUserService sysUserService;
    private final SysRoleDeptService roleDeptService;
    private final SysDeptService sysDeptService;


    @Override
    public String webLogin(String username, String password, HttpServletRequest request) {

        SysUser user = sysUserService.getUserInfoByUserName(username);
        if (ObjectUtils.isEmpty(user)) {
            throw new CustomerException("用户名不存在", null);
        } else if (GlobContants.COMMON_STATUS_NOT_NORMAL.equals(user.getState())) {
            throw new CustomerException("账号已被停用", null);
        }
        if (!BCrypt.checkpw(password, user.getPwd())) {
            throw new CustomerException("用户名或密码错误！", null);
        }
        String place = IpUtils.getIpAddress(request);
        user.setLoginIp(place);
        user.setLoginDate(LocalDateTime.now());
        sysUserService.updateById(user);
        StpUtil.login(user.getUserId());
        return StpUtil.getTokenValue();
    }


    /**
     * 根据用户id构建前端路由树
     *
     * @param userId
     * @return
     */
    public List<Tree<Long>> buildRouterTreeByUser(Long userId) {
        List<Tree<Long>> treeList = null;
        // 获取当前对应角色信息
        List<LoginRole> loginRoles = queryLoginRoleByUserId(userId);
        List<SysMenu> sysMenus = null;
        Boolean isAdmin = checkAdmin(loginRoles);
        if (isAdmin) {
            // 获取所有路由
            sysMenus = sysMenuMapper.selectList(Wrappers.lambdaQuery(SysMenu.class).eq(SysMenu::getMenuType, GlobContants.MENU_TYPE_MENU));
        } else {
            List<Long> list = new ArrayList<>();
            // 按照权限列表获取
            loginRoles.forEach(item -> {
                list.addAll(menuMapper.queryMenuIdsByRoleId(item.getRoleId()));
            });
            List<Long> collect = list.stream().distinct().collect(Collectors.toList());
            sysMenus = queryRouterbyList(collect);
        }
        Long minParentId = getMinParentId(sysMenus);
        List<RouterVo> routerVos = buildRouterList(sysMenus);
        treeList = buildRouterTree(routerVos, minParentId);
        return treeList;
    }


    /**
     * 根据菜单列表构建routervo列表
     *
     * @param list
     * @return
     */
    private List<RouterVo> buildRouterList(List<SysMenu> list) {
        List<RouterVo> voList = null;
        if (CollectionUtils.isNotEmpty(list)) {
            voList = new ArrayList<>();
            for (SysMenu sysMenu : list) {
                RouterVo routerVo = buildRouter(sysMenu);
                voList.add(routerVo);
            }
        }
        return voList;
    }


    /**
     * 树形结构构建
     *
     * @param list
     * @param minParentId
     * @return
     */
    private List<Tree<Long>> buildRouterTree(List<RouterVo> list, Long minParentId) {
        TreeNodeConfig config = new TreeNodeConfig();
        config.setIdKey("routerId");
        config.setParentIdKey("parentId");
        config.setWeightKey("menuSort");
        config.setDeep(5);
        List<Tree<Long>> treeList = TreeUtil.build(list, minParentId, config, (node, tree) -> {

            tree.put("name", node.getName());
            tree.setId(node.getRouterId());
            tree.setParentId(node.getParentId());
            //// 额外的值
            tree.putExtra("component", node.getComponent());
            tree.putExtra("isLink", node.getIsLink());
            tree.put("isLink", node.getIsLink());
            tree.put("menuSort", node.getMenuSort());
            tree.put("path", node.getPath());
            tree.put("redirect", node.getRedirect());
            tree.put("meta", node.getMeta());
        });
        //System.out.println(JSONUtil.toJsonStr(treeList));
        return treeList;
    }


    /**
     * 菜单实体对象转菜单vo
     *
     * @param menu
     * @return
     */
    private RouterVo buildRouter(SysMenu menu) {
        if (ObjectUtil.isEmpty(menu)) return null;
        RouterVo routerVo = new RouterVo();
        routerVo.setRouterId(menu.getMenuId())
                .setTreeNodeName(menu.getTitle())
                .setParentId(menu.getParentId())
                .setName(menu.getMenuName())
                .setComponent(menu.getComponent())
                //.setIsLink(menu.getIsLink().equals(GlobContants.COMMON_STATUS_NORMAL))
                .setMenuSort(menu.getOrderNum())
                .setPath(menu.getPath())
                //.setRedirect("")
                .setMeta(buildMeat(menu));
        return routerVo;
    }


    private MetaVo buildMeat(SysMenu menu) {
        MetaVo metaVo = new MetaVo();
        metaVo.setTitle(menu.getTitle())
                .setIcon(menu.getIcon())
                .setIsHide(menu.getIsHide().equals(GlobContants.COMMON_STATUS_NORMAL))
                .setIsKeepAlive(menu.getIsKeepAlive().equals(GlobContants.COMMON_STATUS_NORMAL))
                .setIsAffix(menu.getIsAffix().equals(GlobContants.COMMON_STATUS_NORMAL))
                .setIsIframe(menu.getIsIframe().equals(GlobContants.COMMON_STATUS_NORMAL));

        if (metaVo.getIsIframe() || menu.getIsLink().equals(GlobContants.COMMON_STATUS_NORMAL)) {
            metaVo.setIsLink(menu.getLink());
        }
        return metaVo;
    }


    /**
     * 根据菜单id获取菜单列表
     *
     * @param list
     * @param minParent
     * @return
     */
    public List<SysMenu> queryRouterbyList(List<Long> list, Long minParent) {
        LambdaQueryWrapper<SysMenu> wrapper = Wrappers.lambdaQuery(SysMenu.class)
                .ne(SysMenu::getMenuType, GlobContants.MENU_TYPE_BUTTON)
                .in(SysMenu::getMenuId, list).eq(SysMenu::getParentId, minParent);
        List<SysMenu> sysMenus = sysMenuMapper.selectList(wrapper);
        return sysMenus;
    }


    /**
     * 获取所有菜单列表
     *
     * @param list
     * @return
     */
    public List<SysMenu> queryRouterbyList(List<Long> list) {
        LambdaQueryWrapper<SysMenu> wrapper = Wrappers.lambdaQuery(SysMenu.class).ne(SysMenu::getMenuType, GlobContants.MENU_TYPE_BUTTON)
                .in(SysMenu::getMenuId, list);
        List<SysMenu> sysMenus = sysMenuMapper.selectList(wrapper);
        return sysMenus;
    }


    /**
     * 给定一个菜单列表获取顶层父id
     *
     * @param list
     * @return
     */
    public Long getMinParentId(List<SysMenu> list) {
        return list.stream().min(Comparator.comparing(SysMenu::getParentId)).get().getParentId();
    }


    /**
     * 给定一个角色列表，判断是否是超级管理员
     *
     * @param list
     * @return
     */
    public Boolean checkAdmin(List<LoginRole> list) {
        boolean falg = false;
        for (LoginRole loginRole : list) {
            if (GlobContants.SUPER_ADMIN.equals(loginRole.getRoleKey())) {
                falg = true;
                break;
            }
        }
        return falg;
    }

    /**
     * 根据用户id获取角色列表
     *
     * @param userId
     * @return
     */
    public List<LoginRole> queryLoginRoleByUserId(Long userId) {
        String key = AuthroticationCacheKeys.AUTH_DATA_SCOPE_USER_ID_LIST + "_user_role_list_#_" + userId;
        List<LoginRole> roles = redisUtils.getCacheList(key);
        if (CollectionUtils.isNotEmpty(roles)) {
            return roles;
        }
        roles =roleMapper.queryLoginRoleByUserId(userId);
        if (CollectionUtils.isNotEmpty(roles)) {
            redisUtils.setCacheList(key,roles);
        }
        return roles;
    }


    /**
     * 根据角色列表和用户id获取对应具备权限的用户id
     *
     * @param list
     * @param userId
     * @return
     */

    private final RedisUtils redisUtils;

    public List<Long> getAuthUserList(List<LoginRole> list, Long userId) {
        String key = AuthroticationCacheKeys.AUTH_DATA_SCOPE_USER_ID_LIST + "_" + userId;

        List<String> cacheList = redisUtils.getCacheList(key);

        if (CollectionUtils.isNotEmpty(cacheList)) {
            return cacheList.stream().map(s -> Long.valueOf(s)).collect(Collectors.toList());
        }
        List<Long> authUserIdList = new ArrayList<>();
        for (LoginRole loginRole : list) {
            if (loginRole.getRoleDataScope().equals("0")) {
                // 获取所有用户数据
                List<Long> collect = sysUserService.list().stream().map(sysUser -> sysUser.getUserId()).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(collect)) {
                    cacheList = collect.stream().map(aLong -> aLong.toString()).collect(Collectors.toList());
                    redisUtils.setCacheList(key, cacheList);
                }
                return collect;
            } else if (loginRole.getRoleDataScope().equals("1")) {
                // 自定义
                List<Long> deptids = roleDeptService.queryDeptIdsByRoleId(loginRole.getRoleId());
                List<Long> userIds = sysUserService.list(Wrappers.lambdaQuery(SysUser.class).in(SysUser::getDeptId, deptids)).stream().map(sysUser -> sysUser.getUserId()).collect(Collectors.toList());
                authUserIdList.addAll(userIds);
            } else if (loginRole.getRoleDataScope().equals("2")) {
                // 本组织数据权限
                List<Long> userIds = sysUserService.list(Wrappers.lambdaQuery(SysUser.class).eq(SysUser::getDeptId, sysUserService.getById(userId).getDeptId())).stream().map(sysUser -> sysUser.getUserId()).collect(Collectors.toList());
                authUserIdList.addAll(userIds);
            } else if (loginRole.getRoleDataScope().equals("3")) {
                // 本组织及所有下级组织
                List<Long> longs = sysDeptService.querySelfAndChildrenIds(sysUserService.getById(userId).getDeptId());
                List<Long> userIds = sysUserService.list(Wrappers.lambdaQuery(SysUser.class).in(SysUser::getDeptId, longs)).stream().map(sysUser -> sysUser.getUserId()).collect(Collectors.toList());
                authUserIdList.addAll(userIds);
            } else if (loginRole.getRoleDataScope().equals("4")) {
                // 仅本人数据
                authUserIdList.add(userId);
            }
        }
        authUserIdList = authUserIdList.stream().distinct().collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(authUserIdList)) {
            cacheList = authUserIdList.stream().map(aLong -> aLong.toString()).collect(Collectors.toList());
            redisUtils.setCacheList(key, cacheList);
        }
        return authUserIdList;
    }


}
